<template>
  <div class="shuttle-box">
    <ShuttleList ref="ShuttleListL" :list="newList.l">
      <template #search="{ searchPage }">
        <slot name="searchL" :searchPage="searchPage"></slot>
      </template>
      <template #default="{ row, index }">
        <span v-if="!hasSlot">{{ row[cusOptions.label] }}</span>
        <slot :row="row" :index="index"></slot>
      </template>
    </ShuttleList>
    <div class="btn-group">
      <button @click="handleTo('ShuttleListR')">&lt;</button>
      <button @click="handleTo('ShuttleListL')">&gt;</button>
    </div>
    <ShuttleList ref="ShuttleListR" :list="newList.r">
      <template #search="{ searchPage }">
        <slot name="searchR" :searchPage="searchPage"></slot>
      </template>
      <template #default="{ row, index }">
        <span v-if="!hasSlot">{{ row[cusOptions.label] }}</span>
        <slot :row="row" :index="index"></slot>
      </template>
    </ShuttleList>
  </div>
</template>
<script lang="ts">
import ShuttleList from "./ShuttleList.vue";
import { difference } from "../../utils/index";
import { computed, defineComponent, PropType, Ref, ref } from "vue";
class ShuttleOptions {
  label = "label";
  value = "value";
}
export default defineComponent({
  emits: ["update:modelValue"],
  components: {
    ShuttleList,
  },
  props: {
    modelValue: {
      type: Array as PropType<StrONum[]>,
      required: true,
    },
    dataList: {
      type: Array,
      required: true,
    },
    options: {
      type: Object,
      default: () => new ShuttleOptions(),
    },
  },
  setup(props, ctx) {
    const cusOptions = computed(() => {
      return { ...new ShuttleOptions(), ...props.options };
    });
    const newList = computed(() => {
      return props.dataList.reduce(
        (acc: { l: any[]; r: any[] }, row: any) => {
          const newRow = {
            ...row,
            value: row[cusOptions.value.value],
            label: row[cusOptions.value.label],
          };
          if (props.modelValue.includes(row[cusOptions.value.value]))
            acc.r.push(newRow);
          else acc.l.push(newRow);
          return acc;
        },
        { l: [], r: [] }
      );
    });
    const refs: { [x: string]: Ref } = {
      ShuttleListL: ref(),
      ShuttleListR: ref(),
    };
    const filterList = (list: StrONum[]) => {
      const newList = difference(list, props.modelValue);
      return newList;
    };
    const handleTo = (refName: string) => {
      const list = refs[refName].value.getSelectedList();
      const newModelList = filterList(list);
      ctx.emit("update:modelValue", newModelList);
    };
    const hasSlot = computed(() => {
      if (ctx.slots.default) {
        const defaultSlot = ctx.slots.default();
        return !!defaultSlot.filter(({ type }) => {
          return typeof type !== "symbol";
        }).length;
      } else {
        return false;
      }
    });

    return {
      cusOptions,
      newList,
      ...refs,
      handleTo,
      hasSlot,
    };
  },
});
</script>
<style scoped>
.shuttle-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 400px;
  width: 800px;
}
.btn-group {
  white-space: nowrap;
  margin: 0 20px;
}
.btn-group button {
  width: 60px;
  height: 40px;
}
.btn-group button:not(:first-of-type) {
  margin-left: 10px;
}
</style>